#include <stdio.h>
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_chip_info.h"
#include "esp_log.h"
#include "ble_module.h"
#include <sys/time.h>
#include <time.h>
#include "nvs.h"
#include "nvs_flash.h"
#if EPD_ENABLE
#include "DEV_Config.h"
#include "EPD_7in5bc.h"
#include "ePaper/lib/GUI/GUI_Paint.h"
#include "test_image_planes.h" // 新增：预编译平面图像
#include "ePaper/lib/Fonts/pingfang_cn.h" // 新增：苹方占位位图字库别名
#include "ePaper/lib/Fonts/pf_sample_text.h" // 新增：脚本生成的GB2312示例文本字节
#endif

static const char *TAG = "calendar";

// 新增：时区偏移（分钟）缓存，默认0（UTC）
static volatile int32_t g_tz_offset_min = 0;

static __attribute__((unused)) int32_t read_tz_offset_from_nvs() {
    nvs_handle_t h;
    int32_t tz = 0;
    esp_err_t err = nvs_open("ble_mod", NVS_READONLY, &h);
    if (err == ESP_OK) {
        err = nvs_get_i32(h, "tz_offset_min", &tz);
        nvs_close(h);
        if (err == ESP_OK) {
            ESP_LOGI(TAG, "从NVS读取时区偏移: %d 分钟", tz);
            return tz;
        } else {
            ESP_LOGW(TAG, "NVS未设置时区偏移，使用默认UTC");
        }
    } else {
        ESP_LOGW(TAG, "打开NVS失败或未初始化，使用默认UTC");
    }
    return 0;
}

// 新增：BLE时间同步回调
static void on_time_sync(uint64_t utc_ms, int16_t tz_offset_min, uint8_t flags) {
    g_tz_offset_min = tz_offset_min;
    ESP_LOGI(TAG, "收到时间同步: utc_ms=%llu, tz_offset_min=%d, flags=0x%02X", (unsigned long long)utc_ms, tz_offset_min, flags);
}

// 新增：时钟打印任务（每秒打印UTC/本地时间与运行时长）
static void clock_task(void *arg) {
    struct timeval start_tv;
    gettimeofday(&start_tv, NULL);
    while (1) {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        // 运行时长
        int64_t uptime_ms = (tv.tv_sec - start_tv.tv_sec) * 1000LL + (tv.tv_usec - start_tv.tv_usec) / 1000LL;
        int64_t up_s = uptime_ms / 1000;
        int h = (int)(up_s / 3600);
        int m = (int)((up_s % 3600) / 60);
        int s = (int)(up_s % 60);
        // UTC时间
        time_t sec = tv.tv_sec;
        struct tm tm_utc;
        gmtime_r(&sec, &tm_utc);
        // 本地时间（根据偏移分钟）
        int32_t offset_sec = g_tz_offset_min * 60;
        time_t local_sec = sec + offset_sec;
        struct tm tm_local;
        gmtime_r(&local_sec, &tm_local);
        ESP_LOGI(TAG, "UTC %04d-%02d-%02d %02d:%02d:%02d | Local(%+03d:%02d) %04d-%02d-%02d %02d:%02d:%02d | Uptime %02d:%02d:%02d",
                 tm_utc.tm_year + 1900, tm_utc.tm_mon + 1, tm_utc.tm_mday, tm_utc.tm_hour, tm_utc.tm_min, tm_utc.tm_sec,
                 (int)(g_tz_offset_min / 60), (int)abs(g_tz_offset_min % 60),
                 tm_local.tm_year + 1900, tm_local.tm_mon + 1, tm_local.tm_mday, tm_local.tm_hour, tm_local.tm_min, tm_local.tm_sec,
                 h, m, s);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

#if EPD_ENABLE
static inline UWORD plane_size_bytes(UWORD w, UWORD h) {
    return (UWORD)((w * h) / 8);
}

static inline void set_bit(uint8_t *buf, UWORD w, UWORD x, UWORD y, bool value) {
    UWORD byte_index = y * (w / 8) + (x / 8);
    UBYTE mask = 0x80u >> (x & 7u);
    if (value) {
        buf[byte_index] |= mask;
    } else {
        buf[byte_index] &= (UBYTE)(~mask);
    }
}

// 使用厂商驱动进行一次全屏刷新验证
static void epd_vendor_full_refresh_once(void) {
    ESP_LOGI(TAG, "EPD厂商驱动验证开始");
    if (DEV_Module_Init() != 0) {
        ESP_LOGE(TAG, "DEV_Module_Init失败");
        return;
    }
    EPD_7IN5BC_Init();
    ESP_LOGI(TAG, "EPD_7IN5BC_Init完成，准备清屏");
    EPD_7IN5BC_Clear();
    ESP_LOGI(TAG, "EPD_7IN5BC_Clear已调用，等待屏幕忙信号结束");
    EPD_7IN5BC_Sleep();
    DEV_Module_Exit();
    ESP_LOGI(TAG, "EPD厂商驱动验证完成(已休眠)");
}

// 新增：显示预编译BMP转换平面，以确认坐标与颜色映射
static void epd_vendor_display_compiled_image_blocking(void) {
    // 注意：不在此函数中休眠/退出，以便后续继续刷新
    ESP_LOGI(TAG, "显示预编译BMP平面（初始全屏）");
    EPD_7IN5BC_Display(TEST_BW_PLANE, TEST_RY_PLANE);
}

// 新增：局部刷新能力验证（基于全屏刷新驱动，进行局部内容变更）
static void epd_partial_refresh_emulation_test(void) {
    // 初始化与首次全屏显示
    if (DEV_Module_Init() != 0) {
        ESP_LOGE(TAG, "DEV_Module_Init失败");
        return;
    }
    EPD_7IN5BC_Init();

    const UWORD W = EPD_7IN5BC_WIDTH;
    const UWORD H = EPD_7IN5BC_HEIGHT;
    const UWORD width_bytes = (W % 8 == 0) ? (W / 8) : (W / 8 + 1);
    const size_t full_data_bytes = (size_t)H * width_bytes * 8; // 依据厂商驱动内循环，显示时每行发送 width_bytes*8 字节

    // 1) 初始状态：显示完整BMP图像
    struct timeval t0, t1;
    gettimeofday(&t0, NULL);
    epd_vendor_display_compiled_image_blocking();
    gettimeofday(&t1, NULL);
    long init_ms = (t1.tv_sec - t0.tv_sec) * 1000L + (t1.tv_usec - t0.tv_usec) / 1000L;
    ESP_LOGI(TAG, "初始全屏显示完成 | 估算传输数据量: %zu 字节 | 耗时: %ld ms", full_data_bytes, init_ms);
    ESP_LOGI(TAG, "设备端存储占用估算: BW平面 %u 字节, RY平面 %u 字节, 总计 ~%u 字节 (仅图像数据)", width_bytes * H, width_bytes * H, width_bytes * H * 2);

    // 准备可变平面（从预编译平面拷贝）
    UWORD SZ = plane_size_bytes(W, H);
    UBYTE *bw = (UBYTE *)malloc(SZ);
    UBYTE *ry = (UBYTE *)malloc(SZ);
    if (!bw || !ry) {
        ESP_LOGE(TAG, "内存分配失败: %u 字节", (unsigned)SZ);
        free(bw); free(ry);
        EPD_7IN5BC_Sleep();
        DEV_Module_Exit();
        return;
    }
    memcpy(bw, TEST_BW_PLANE, SZ);
    memcpy(ry, TEST_RY_PLANE, SZ);

    // 居中白色区域坐标范围（BMP预期：中间1/3为白）
    UWORD x_start = W / 3;
    UWORD x_end   = (W * 2) / 3; // [x_start, x_end)

    // 2) 第一次局部刷新测试（10秒后）：仅将中央白色区域改为红色
    vTaskDelay(10000 / portTICK_PERIOD_MS);
    gettimeofday(&t0, NULL);
    for (UWORD y = 0; y < H; ++y) {
        for (UWORD x = x_start; x < x_end; ++x) {
            set_bit(bw, W, x, y, true);  // 保持白底（不黑）
            set_bit(ry, W, x, y, false); // 设置红色（RY位=0）
        }
    }
    EPD_7IN5BC_Display(bw, ry);
    gettimeofday(&t1, NULL);
    long part1_ms = (t1.tv_sec - t0.tv_sec) * 1000L + (t1.tv_usec - t0.tv_usec) / 1000L;
    ESP_LOGI(TAG, "局部刷新#1完成(视觉仅中间区域变红) | 实际驱动为全屏波形刷新 | 估算传输数据量: %zu 字节 | 耗时: %ld ms", full_data_bytes, part1_ms);

    // 3) 第二次局部刷新测试（再20秒后）：将红色改回白色
    vTaskDelay(20000 / portTICK_PERIOD_MS);
    gettimeofday(&t0, NULL);
    for (UWORD y = 0; y < H; ++y) {
        for (UWORD x = x_start; x < x_end; ++x) {
            set_bit(bw, W, x, y, true);  // 白底
            set_bit(ry, W, x, y, true);  // 无红
        }
    }
    EPD_7IN5BC_Display(bw, ry);
    gettimeofday(&t1, NULL);
    long part2_ms = (t1.tv_sec - t0.tv_sec) * 1000L + (t1.tv_usec - t0.tv_usec) / 1000L;
    ESP_LOGI(TAG, "局部刷新#2完成(视觉中间区域恢复白色) | 实际驱动为全屏波形刷新 | 估算传输数据量: %zu 字节 | 耗时: %ld ms", full_data_bytes, part2_ms);

    // 验证指标总结
    ESP_LOGI(TAG, "验证指标总结：\n- 全屏 vs 局部视觉变更的传输量(估算)相同: %zu 字节\n- 刷新过程中可能出现整屏闪烁，这是三色墨水屏的全屏波形特性\n- 设备端数据更新方式：当前驱动按全屏缓冲写入，不支持增量局部传输命令(窗口更新)\n- 若需严格意义的“局部刷新/数据量显著降低”，需要更换支持局部波形的黑白面板或底层新增窗口写入支持(取决于控制器)",
             full_data_bytes);

    // 释放与休眠
    free(bw);
    free(ry);
    EPD_7IN5BC_Sleep();
    DEV_Module_Exit();
}
#endif

#if EPD_ENABLE
// 面板物理尺寸(近似值，建议以实际规格或标定替换)
#define PANEL_WIDTH_PX   640
#define PANEL_HEIGHT_PX  384
#define PANEL_WIDTH_MM   163.0f
#define PANEL_HEIGHT_MM  98.0f

static inline int mm_to_px_x(float mm) {
    return (int)lroundf(mm * (float)PANEL_WIDTH_PX / PANEL_WIDTH_MM);
}
static inline int mm_to_px_y(float mm) {
    return (int)lroundf(mm * (float)PANEL_HEIGHT_PX / PANEL_HEIGHT_MM);
}

// 新增：绘制2cm红色边框+中心中文(苹方占位)并显示
static void epd_draw_red_border_and_pingfang_text_demo(void) {
    ESP_LOGI(TAG, "绘制红色边框+中心中文(PingFang占位)演示开始");
    if (DEV_Module_Init() != 0) {
        ESP_LOGE(TAG, "DEV_Module_Init失败");
        return;
    }
    EPD_7IN5BC_Init();

    const UWORD W = EPD_7IN5BC_WIDTH;   // 640
    const UWORD H = EPD_7IN5BC_HEIGHT;  // 384
    const UWORD plane_bytes = (W * H) / 8;
    UBYTE *bw = (UBYTE *)malloc(plane_bytes);
    UBYTE *ry = (UBYTE *)malloc(plane_bytes);
    if (!bw || !ry) {
        ESP_LOGE(TAG, "内存分配失败: %u 字节", (unsigned)plane_bytes);
        free(bw); free(ry);
        EPD_7IN5BC_Sleep();
        DEV_Module_Exit();
        return;
    }
    memset(bw, 0xFF, plane_bytes); // 白
    memset(ry, 0xFF, plane_bytes); // 白

    // RY平面：绘制2cm红色边框（四边等宽、实线）
    Paint_NewImage(ry, W, H, ROTATE_0, WHITE);
    Paint_SelectImage(ry);
    Paint_SetScale(2);
    Paint_Clear(WHITE);

    int border_px = mm_to_px_y(20.0f); // 2cm = 20mm
    if (border_px < 1) border_px = 1;

    // 上边框
    Paint_DrawRectangle(0, 0, W - 1, border_px - 1, RED, DOT_PIXEL_1X1, DRAW_FILL_FULL);
    // 下边框
    Paint_DrawRectangle(0, H - border_px, W - 1, H - 1, RED, DOT_PIXEL_1X1, DRAW_FILL_FULL);
    // 左边框
    Paint_DrawRectangle(0, border_px, border_px - 1, H - border_px - 1, RED, DOT_PIXEL_1X1, DRAW_FILL_FULL);
    // 右边框
    Paint_DrawRectangle(W - border_px, border_px, W - 1, H - border_px - 1, RED, DOT_PIXEL_1X1, DRAW_FILL_FULL);

    // BW平面：居中绘制中文(苹方占位 -> Font24CN)
    Paint_NewImage(bw, W, H, ROTATE_0, WHITE);
    Paint_SelectImage(bw);
    Paint_SetScale(2);
    Paint_Clear(WHITE);

    const char *text = PF_SAMPLE_TEXT_GB2312; // 使用GB2312字节数组，避免源文件UTF-8编码问题
    // 内部可视区域(减边框+文字边距，5mm)
    int margin_px_x = mm_to_px_x(5.0f);
    int margin_px_y = mm_to_px_y(5.0f);
    int inner_left   = border_px + margin_px_x;
    int inner_right  = W - 1 - border_px - margin_px_x;
    int inner_top    = border_px + margin_px_y;
    int inner_bottom = H - 1 - border_px - margin_px_y;
    if (inner_left > inner_right)  inner_left = inner_right;
    if (inner_top > inner_bottom)  inner_top = inner_bottom;

    // 简单字符计数(ASCII1字节/中文2字节)用于居中估算
    int ch_cnt = 0; const unsigned char *p = (const unsigned char *)text;
    while (*p) { if (*p < 0x80) { ch_cnt++; p++; } else { ch_cnt++; p += 2; } }

    int text_w = ch_cnt * PingFang24CN.Width; // 占位：使用 Font24CN 宽度
    int text_h = PingFang24CN.Height;
    int inner_w = inner_right - inner_left + 1;
    int inner_h = inner_bottom - inner_top + 1;
    // 计算初始居中位置（水平+垂直）
    int x = inner_left + (inner_w - text_w) / 2;
    int y = inner_top + (inner_h - text_h) / 2;
    int baseline_adj = 2; // 按你的要求：向下微调 2 像素
    // 应用基线调整
    y += baseline_adj;
    // 使用一次性钳位，避免顺序导致越界
    if (y > inner_bottom - text_h) y = inner_bottom - text_h;
    if (y < inner_top) y = inner_top;
    // 调试：绘制两条参考线和日志以验证位置是否生效
    Paint_DrawLine(x - 20, y, x + text_w + 20, y, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
    Paint_DrawLine(x - 20, inner_top + (inner_h - text_h) / 2, x + text_w + 20, inner_top + (inner_h - text_h) / 2, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
    // 文本区域可视化：绘制文本矩形边框、顶部/底部边界线，帮助判断是否发生底部裁剪
    Paint_DrawRectangle(x, y, x + text_w - 1, y + text_h - 1, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);
    Paint_DrawLine(x - 20, y, x + text_w + 20, y, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
    Paint_DrawLine(x - 20, y + text_h - 1, x + text_w + 20, y + text_h - 1, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
    ESP_LOGI("calendar", "text_w=%d text_h=%d inner_top=%d inner_bottom=%d inner_h=%d x_center=%d y_top=%d y_bottom=%d", text_w, text_h, inner_top, inner_bottom, inner_h, x, y, y + text_h - 1);

    Paint_DrawString_CN(x, y, text, &PingFang24CN, BLACK, WHITE);

    // 显示与收尾
    EPD_7IN5BC_Display(bw, ry);
    EPD_7IN5BC_Sleep();
    DEV_Module_Exit();

    free(bw);
    free(ry);
    ESP_LOGI(TAG, "演示完成并休眠");
}
#endif

void app_main(void)
{
    ESP_LOGI(TAG, "日历应用启动");
    ESP_LOGI(TAG, "ESP32-DOWD-V3开发板环境配置完成");
    
    // 打印芯片信息
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    ESP_LOGI(TAG, "芯片型号: %s", CONFIG_IDF_TARGET);
    ESP_LOGI(TAG, "核心数: %d", chip_info.cores);
    ESP_LOGI(TAG, "功能: %s%s%s%s%d%s", 
             (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi" : "",
             (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
             (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
             " 修订版: ", chip_info.revision,
             " MB");

    // 打印内存信息
    ESP_LOGI(TAG, "空闲堆内存: %d 字节", esp_get_free_heap_size());
    
    // 初始化BLE模块（极简版本）
    esp_err_t ret = ble_init();
    if (ret == ESP_OK) {
        // 注册时间同步回调
        ble_register_time_sync_callback(on_time_sync);
        // 启动时钟打印任务
        xTaskCreate(clock_task, "clock_task", 4096, NULL, 5, NULL);
    } else {
        ESP_LOGE(TAG, "BLE初始化失败: %s", esp_err_to_name(ret));
    }

#if EPD_ENABLE
    // 执行红色边框+居中文本演示
    epd_draw_red_border_and_pingfang_text_demo();
    // 旧：局部刷新能力验证（暂时注释）
    // epd_partial_refresh_emulation_test();
#endif
}